var running      = false,
    lastScores   = [],
    totals       = [],
    testFns      = [],
    selectorNdx  = 0,
    frameworkNdx = 0,
    loadedFrames = 0,
    numFrameworks = 0,
    iterations,
    timeout,
    minMargin,
    timer;


document.observe('dom:loaded', function(){
  var table     = $('resultTable'), 
      startStop = $('startStop'),
      html      = '<table><thead><tr><th>selectors</th>', 
      now       = new Date().getTime(),
      i, name, framework, iframe;
  
  for (name in frameworks) {
    numFrameworks++;
    framework = frameworks[name];
    html += '<td class="framework">' + name + '</td>';
    
    iframe = new Element('iframe', {
      name: name,
      time: preventCaching ? now : 0, 
      src : testDocURL + '?src=' + framework.src + 
            '&selectorFn=' + framework.selectorFn
    });
    document.body.appendChild(iframe);
    
    iframe.observe('load', function() 
    {
      if(++loadedFrames == numFrameworks) {   
        startStop.innerHTML = "start";
        startStop.observe("click", startTests);
      }
    });
  }
  
  html += '</tr></thead><tbody id="results"></tbody><tfoot id="totals">' +
  '<tr> <th id="totals">Running total (less is better)</th>';
  
  for (i = 0; i < numFrameworks; i++) 
    html += '<td id="score' + i + '" class="score">0</td>';
  
  html += '</tr></tfoot></table>';
  table.innerHTML = html;
  $('iterations').value = defaultIterations;
  $('timeout').value = defaultTimeout;    
  $('minMargin').value = defaultMinMargin;    
});

function startTests(event) {           
  iterations = $('iterations').value;
  minMargin  = $('minMargin').value;  
  timeout    = $('timeout').value;       
  
  $$('iframe').each(function(iframe, index){
    testFns[index] = window.frames[iframe.name].test;
    totals[index] = 0;
  });

  if(running) 
    stopTests();
  else {
    this.innerHTML = 'stop';
    $('results').innerHTML = '';
    selectorNdx = frameworkNdx = 0;
    running = true;
	  runNext();
  }
  
  event.preventDefault();
}

function stopTests()
{
  $('startStop').innerHTML = 'start';
  running = false;
  clearTimeout(timer);
}

function runNext() {  
  var s = selectors[selectorNdx], result, html, cells, cell, className, i;
  
  if(frameworkNdx == 0)
    $('results').innerHTML += '<tr id="row' + selectorNdx + '"><th>' + 
      selectors[selectorNdx].selector + '</th>' + 
      '<td class="empty"></td>'.times(numFrameworks) + '</tr>';    
  
  cells = $('row' + selectorNdx).select('td');
  cell  = cells[frameworkNdx];
  cell.innerHTML = 'running test...';
  
  result = testFns[frameworkNdx](s.selector, s.expected, iterations, timeout);
  lastScores[frameworkNdx] = result.elapsed || 0;
  
  if(result.broken) {
    cell.className = 'broken';
    cell.innerHTML = 'Expected: ' + s.expected + ', Got: ' + result.actual;
  }
  else if(result.error) {
    cell.title = result.error.toString();
    cell.className = 'exception';
    cell.innerHTML = "an error was thrown";
  }
  else {
    totals[frameworkNdx] += result.elapsed;
    cell.className = '';
    cell.innerHTML = result.elapsed.toFixed(1) + ' ms';
  }  
        
  if(++frameworkNdx >= numFrameworks) {   
    var sortedScores = lastScores.slice(0).sort(function(a, b) { 
          return a < b ? -1 : a > b ? 1 : 0; 
        }),
        slowest = sortedScores.length - 1;
  
    for(i = 0; i < cells.length; i++) {
      if(cells[i].className == 'exception' || cells[i].className == 'broken')
        totals[i] += sortedScores[slowest];
      else if(lastScores[i] - sortedScores[0] <= minMargin)
        cells[i].className = 'fast';
      else if(sortedScores[slowest] - lastScores[i] <= minMargin)
        cells[i].className = 'slow';
    }
    
    $$('#totals td').each(function(cell, index) {
      cell.innerHTML = totals[index].toFixed(1) + ' ms';
    });  
      
    frameworkNdx = 0;
    
    if(++selectorNdx >= selectors.length) {
      stopTests();  
      return;
    }    
  }
  
  timer = setTimeout(runNext, 50);
}

